<?php

namespace app\queue\stomp;

use Webman\Stomp\Client;
use app\queue\BaseConsumer;
use common\model\TaskModel;
use common\model\EntityModel;

class CheckOverdueEntityTaskConsumer extends BaseConsumer
{
    // 要消费的队列名
    public $queue = 'check_overdue_entity_task';

    // 连接名，对应 config/redis_queue.php 里的连接`
    public $connection = 'default';

    public function doConsume($data)
    {
        $taskFilter = $data['task_filter'];
        $taskFilter['project_id'] = $data['project_item'];
        $entityModuleFilter = [
            'entity_module_id' => ['IN', array_column($data['module_list'], 'id')]
        ];
        $data['p'] = $data['p'] ?? 0;

        $data['p'] += 1;
        // 获取所有指定的逾期任务
        $entityTaskList = model(TaskModel::class)
            ->where($taskFilter)
            ->where($entityModuleFilter)
            ->page($data['p'], C("database.database_max_select_rows"))
            ->select();
        if (empty($entityTaskList)) {
            return;
        }

        $this->handleEntityData($data, $entityTaskList);
        //检查处理完实体状态信息后，回调
        Client::send("check_overdue_entity_task", build_queue_data_with_xu($data), 3);
    }

    /**
     * 检查实体逾期数据
     * @param $data
     * @param $entityTaskList
     * @return void
     */
    private function handleEntityData($data, $entityTaskList)
    {
        $publicFilter = $data['public_filter'];
        $moduleCodeMap = $data['module_code_map'];
        $upstreamEntity = $data['upstream_entity'];
        $downstreamEntity = $data['downstream_entity'];
        $projectIdFilter = [
            'project_id' => $data['project_item'],
        ];
        $entityModuleFilter = [
            'entity_module_id' => ['IN', array_column($data['module_list'], 'id')]
        ];
        $upstreamEntityIds = [];
        $downstreamEntityIds = [];
        $maxTmpEntityStepCategoryStepTaskIdListFilter = [];
        $needUpdateOverdueStepTaskIdList = [];

        foreach ($entityTaskList as $entityTaskItem) {
            $entityTaskItem['json'] = json_decode($entityTaskItem['json'], true);
            if (!isset($entityTaskItem['json']['task_is_overdue']) || $entityTaskItem['json']['task_is_overdue'] !== 'yes') {
                $needUpdateOverdueStepTaskIdList[] = $entityTaskItem['id'];
            }
            $maxTmpEntityStepCategoryStepTaskIdListFilter[sprintf("%s#%s", $entityTaskItem['entity_id'], $entityTaskItem['step_category_id'])] = [
                'entity_id' => $entityTaskItem['entity_id'],
                'step_category_id' => $entityTaskItem['step_category_id'],
            ];
        }
        // 更新逾期的工序任务为已逾期
        if (!empty($needUpdateOverdueStepTaskIdList)) {
            $needUpdateOverdueStepTaskIdList = implode(',', $needUpdateOverdueStepTaskIdList);
            model(TaskModel::class)->execute("UPDATE task SET json = JSON_SET(IFNULL(json, '{}'), concat('$.task_is_overdue'), 'yes') where id in ($needUpdateOverdueStepTaskIdList)");
        }

        // 获取每个实体下面每个环节里面最后一个工序任务
        $maxEntityStepCategoryStepTaskIdListFilter[0] = array_values($maxTmpEntityStepCategoryStepTaskIdListFilter);
        $maxEntityStepCategoryStepTaskIdListFilter[0]['_logic'] = 'or';
        $maxEntityStepCategoryStepTaskIdListFilter[] = [
            'step_type' => 'step',
        ];
        $maxEntityStepCategoryStepTaskIdList = model(TaskModel::class)
            ->where($maxEntityStepCategoryStepTaskIdListFilter)
            ->where($entityModuleFilter)
            ->where($projectIdFilter)
            ->field('max(id) as id,entity_id,step_category_id')
            ->group('entity_id,step_category_id')
            ->select();
        if (empty($maxEntityStepCategoryStepTaskIdList)) {
            return;
        }
        $entityStepCategoryTaskOverdueList = model(TaskModel::class)
            ->where(['id' => ['in', array_column($maxEntityStepCategoryStepTaskIdList, 'id')]])
            ->where([$publicFilter])
            ->field('entity_id,step_category_id')
            ->select();
        if (empty($entityStepCategoryTaskOverdueList)) {
            return;
        }
        $entityStepCategoryTaskListFilter = [];

        foreach ($entityStepCategoryTaskOverdueList as $entityStepCategoryTaskOverdueItem) {
            $entityStepCategoryTaskListFilter[0][] = [
                'entity_id' => $entityStepCategoryTaskOverdueItem['entity_id'],
                'step_category_id' => $entityStepCategoryTaskOverdueItem['step_category_id'],
            ];
        }
        $entityStepCategoryTaskListFilter[0]['_logic'] = 'or';
        $entityStepCategoryTaskListFilter[] = [
            'step_type' => 'step_category'
        ];
        $entityStepCategoryTaskListQueryFields = [
            'id',
            'name',
            'task_is_overdue',
            'entity_module_id',
            'entity_id',
        ];
        $entityStepCategoryTaskList = model(TaskModel::class)
            ->where($entityStepCategoryTaskListFilter)
            ->where($projectIdFilter)
            ->where($entityModuleFilter)
            ->field(transform_custom_fields($entityStepCategoryTaskListQueryFields, 'task'))
            ->select();

        $entityIsOverDueMap = [];
        $upEntityStepCategoryTaskIds = [];
        foreach ($entityStepCategoryTaskList as $entityStepCategoryTaskItem) {
            $entityIsOverDueMap[$entityStepCategoryTaskItem['entity_id']] = [
                'entity_id' => $entityStepCategoryTaskItem['entity_id'],
                'entity_module_id' => $entityStepCategoryTaskItem['entity_module_id'],
            ];
            if ($entityStepCategoryTaskItem['task_is_overdue'] === 'yes') {
                continue;
            }
            $upEntityStepCategoryTaskIds[] = (int)$entityStepCategoryTaskItem['id'];
        }
        if (empty($upEntityStepCategoryTaskIds)) {
            return;
        }
        $upEntityStepCategoryTaskIds = implode(',', $upEntityStepCategoryTaskIds);
        model(TaskModel::class)->execute("UPDATE task SET json = JSON_SET(IFNULL(json, '{}'), concat('$.task_is_overdue'), 'yes') where id in ($upEntityStepCategoryTaskIds)");

        // 获取上游实体ID以及下游实体ID
        foreach ($entityIsOverDueMap as $datum) {
            if (empty($moduleCodeMap[$datum['entity_module_id']])) {
                continue;
            }
            if (in_array($moduleCodeMap[$datum['entity_module_id']], $upstreamEntity)) {
                $upstreamEntityIds[] = $datum['entity_id'];
            } else if (in_array($moduleCodeMap[$datum['entity_module_id']], $downstreamEntity)) {
                $downstreamEntityIds[] = $datum['entity_id'];
            }
        }
        // 下游实体需要直接追溯到上游的实体
        if (!empty($downstreamEntityIds)) {
            $downstreamEntityIds = array_unique($downstreamEntityIds);
            $entityList = model(EntityModel::class)->field(
                "json_unquote(json_extract(json, '$.asset_design')) as asset_design_id,
                json_unquote(json_extract(json, '$.level_design')) as level_design_id,
                json_unquote(json_extract(json, '$.shot_storyboard')) as shot_storyboard_id"
            )->where(['id' => ['IN', $downstreamEntityIds]])->select();
            $assetDesignIds = array_values(array_filter(array_column($entityList, 'asset_design_id')));
            if (!empty($assetDesignIds)) {
                $upstreamEntityIds = array_merge($upstreamEntityIds, $assetDesignIds);
            }
            $levelDesignIds = array_values(array_filter(array_column($entityList, 'level_design_id')));
            if (!empty($levelDesignIds)) {
                $upstreamEntityIds = array_merge($upstreamEntityIds, $levelDesignIds);
            }
            $shotStoryboardIds = array_values(array_filter(array_column($entityList, 'shot_storyboard_id')));
            if (!empty($shotStoryboardIds)) {
                $upstreamEntityIds = array_merge($upstreamEntityIds, $shotStoryboardIds);
            }
        }
        if (empty($upstreamEntityIds)) {
            return;
        }
        $upstreamEntityIds = implode(',', array_unique($upstreamEntityIds));
        // 跳过已经有异常状态且异常状态为yes的实体
        $upstreamEntityList = model(EntityModel::class)
            ->field("entity.id,
            json_unquote(json_extract(entity.json, concat('$.',m.code, '_is_abnormal'))) as is_abnormal"
            )->join('module m on m.id = entity.module_id')
            ->where(['entity.id' => ['IN', $upstreamEntityIds]])
            ->select();
        $entityIds = [];
        foreach ($upstreamEntityList as $upstreamEntityItem) {
            if (!empty($upstreamEntityItem['is_abnormal']) && $upstreamEntityItem['is_abnormal'] == 'yes') {
                continue;
            }
            $entityIds[] = $upstreamEntityItem['id'];
        };
        if (empty($entityIds)) {
            return;
        }
        $entityIds = implode(',', $entityIds);

        model(EntityModel::class)->execute("
            UPDATE entity join module m on m.id = entity.module_id 
            SET entity.json = JSON_SET(IFNULL(entity.json, '{}'),
            concat('$.',m.code, '_is_abnormal'), 'yes') 
            where entity.id in ($entityIds)"
        );
    }
}
